home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
CW GUSI 1.6.4
/
src
/
GUSIGlob.cp
< prev
next >
Wrap
Text File
|
1995-10-31
|
4KB
|
259 lines
/*********************************************************************
Project : GUSI - Grand Unified Socket Interface
File : GUSIGlob.cp - Expand wildcard characters
Author : Matthias Neeracher <neeri@iis.ethz.ch>
Language : MPW C
$Log: GUSIFile.cp,v $
*********************************************************************/
#include <ctype.h>
#include <TextUtils.h>
#include "GUSIFile_P.h"
#include "TFileGlob.h"
#pragma segment GUSI
/* Slice up and count segments. To deal with aliases, "::"s actually
count as an empty segment
*/
static int SliceSegments(char * pattern)
{
int segments = 1;
for (; *pattern; ++pattern)
if (*pattern == ':') {
*pattern = 0;
if (pattern[1])
++segments;
}
return segments;
}
static Boolean HasWildCards(char * pattern)
{
for (;;) {
switch (*pattern) {
case '?':
case '*':
case '≈':
return true;
case '\\':
case '∂':
if (*++pattern)
break;
// Else fall through
case 0:
return false;
default:
break;
}
++pattern;
}
return false;
}
TFileGlob::TFileGlob(const char * pattern, const TFileSpec * startDir)
: TFileSpec(), patBuf(nil), track(nil)
{
if (!*pattern)
error = bdNamErr;
else if (*pattern != ':' && strchr(pattern, ':')) // full path pattern
Root();
else if (startDir)
*(TFileSpec *)this = *startDir;
else
Default();
if (*pattern == ':') {
++pattern;
if (!*pattern) { // Very special case ":"
segments = 0;
valid = true;
return;
}
}
int patlen = strlen(pattern);
if (!(valid = !error) || !(patBuf = new char[patlen+1]))
return;
memcpy(patBuf, pattern, patlen+1);
UppercaseText(patBuf, patlen, smSystemScript);
int segCount = SliceSegments(patBuf);
if (segCount > 127) {
error = bdNamErr;
return;
}
if (!(track = new BackTrack[segCount]))
return;
segments = segCount;
char * patSeg = patBuf;
for (segCount = 0; segCount < segments; patSeg += strlen(patSeg)+1) {
track[segCount].index = HasWildCards(patSeg) ? 0 : -1;
track[segCount++].pattern = patSeg;
}
// Volume names always have to be matched exhaustively
if (IsRoot())
track[0].index = 0;
valid = Next(track, segments, true);
}
Boolean TFileGlob::Next()
{
for (int depth = segments; depth--; )
if (valid = Next(track+depth, segments - depth))
return true;
return valid = false;
}
static Boolean MatchName(const char * name, const char * pattern, int nameLen)
{
while (nameLen--) {
switch (*pattern) {
case '\\':
case '∂':
if (!*++pattern)
--pattern; // special case at end of pattern
// Fall through
default:
if (toupper(*name) != *pattern)
return false;
// Fall through
case '?':
++name;
++pattern;
break;
case '*':
case '≈':
while (!MatchName(name, pattern+1, nameLen+1)) {
if (nameLen-- < 0)
return false; // "a", "*b"
++name; // "ba", "*a" or "ba", "*b"
}
return true; // "a", "*a"
}
}
while (*pattern)
switch (*pattern) {
case '*':
case '≈':
++pattern;
break;
default:
return false;
}
return true;
}
Boolean TFileGlob::Next(BackTrack * track, int depth, Boolean init)
{
if (!depth) {
if (!Exists())
return false;
Bless();
return true;
}
if (track->index == -1) { // Exact match
if (!init) // Won't match again
return false;
if (!*track->pattern)
--*this;
else
*this += track->pattern;
return Error() ? false : Next(track+1, depth - 1, true);
}
if (init) {
*this += "";
if (Error())
return false;
track->index = 0;
track->vRefNum = vRefNum;
track->parID = parID;
}
for (;;) {
vRefNum = track->vRefNum;
parID = track->parID;
*(TFileSpec *)this = (*this)[++track->index];
if (Error())
break;
static char uprName[64];
memcpy(uprName, name+1, *name);
UppercaseText(uprName, *name, smSystemScript);
if (!MatchName((char *)name+1, track->pattern, *name))
continue;
if (Next(track+1, depth - 1, true))
return true;
}
return false;
}
// C glue
FileGlobRef NewFileGlob(const char * pattern)
{
FileGlobRef glob = new TFileGlob(pattern);
if (!glob->Error())
return glob;
delete glob;
return nil;
}
Boolean NextFileGlob(FileGlobRef glob)
{
return glob->Next();
}
Boolean FileGlob2FSSpec(FileGlobRef glob, FSSpec * spec)
{
if (glob->Valid())
*spec = *(FSSpec *) glob;
return glob->Valid();
}
void DisposeFileGlob(FileGlobRef glob)
{
delete glob;
}